package org.smartboot.flow.helper.view;

import org.smartboot.flow.core.FlowEngine;
import org.smartboot.flow.core.visitor.EngineVisitor;
import org.smartboot.flow.core.visitor.PipelineVisitor;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * @author qinluo
 * @date 2022-11-14 19:48:14
 * @since 1.0.5
 */
public class XmlEngineVisitor extends EngineVisitor {

    private static final String START = "\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<engines xmlns=\"http://org.smartboot/smart-flow\"\n" +
            "       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
            "       xsi:schemaLocation=\"http://org.smartboot/smart-flow\n" +
            "                           http://org.smartboot/smart-flow-1.0.1.xsd\">";

    private static final String END = "</engines>";

    /**
     * engine name.
     */
    private String name;
    private XmlPipelineVisitor pipeline;

    /**
     * Xml content.
     */
    private String content;

    /**
     * 记录访问过的对象
     */
    private final Set<Object> visited = new HashSet<>();

    public String getContent() {
        return content;
    }

    public <T, S> void visit(FlowEngine<T, S> engine) {
        engine.visit(this);
    }

    @Override
    public void visitEnd() {
        ScriptCollector.start();

        StringBuilder content = new StringBuilder();
        content.append(START).append("\n");
        // <engine name="" pipeline=""/>
        content.append("\t<engine name=\"").append(name).append("\" pipeline=\"").append(pipeline.getName()).append("\"/>\n");

        // Pipeline
        this.pipeline.generate(content, 1);

        Map<String, String> scripts = ScriptCollector.end();
        if (scripts != null && scripts.size() > 0) {
            scripts.forEach((k, v) -> {
                content.append("\n\t<script type=\"").append(k)
                        .append("\">\n\t\t").append(v).append("\n\t</script>");
            });
        }

        content.append("\n").append(END).append("\n");

        this.content = content.toString();
    }

    @Override
    public void visit(String engine, Executor executor) {
        this.name = engine;
    }

    @Override
    public PipelineVisitor visitPipeline(String pipeline) {
        this.pipeline = new XmlPipelineVisitor(pipeline, visited);
        return this.pipeline;
    }
}
